/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.csp.sentinel.dashboard.rule.zookeeper;

import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class ZookeeperConfigUtilEx<T> {

    /**
     * 写入规则
     *
     * @param app
     * @param rules
     * @param rulePath
     * @param zkClient
     * @param converter
     * @param serverPort
     * @param <T>
     */
    public static <T> void publish2(
            String app,
            List rules,
            String rulePath,
            CuratorFramework zkClient,
            Converter converter,
            Integer serverPort
    ) {
        publishCommon(app, rules, rulePath, zkClient, converter, serverPort);
    }

    /**
     * 写入规则
     *
     * @param <T>
     * @param app
     * @param rules
     * @param rulePath
     * @param zkClient
     * @param converter
     */
    public static <T> void publish(
            String app,
            List rules,
            String rulePath,
            CuratorFramework zkClient,
            Converter converter
    ) {
        publishCommon(app, rules, rulePath, zkClient, converter, null);
    }

    protected static void publishCommon(String app,
                                        List rules,
                                        String rulePath,
                                        CuratorFramework zkClient,
                                        Converter converter,
                                        Integer serverPort) {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        try {
            String path;
            if (null != serverPort) {
                path = String.format(rulePath, app, serverPort);
            } else {
                path = String.format(rulePath, app);
            }
            Stat stat = zkClient.checkExists().forPath(path);
            if (stat == null) {
                zkClient.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, null);
            }
            byte[] data = new byte[0];
            if (!CollectionUtils.isEmpty(rules)) {
                Object convert = converter.convert(rules);
                data = convert.toString().getBytes();
            }
            zkClient.setData().forPath(path, data);
        } catch (Exception e) {
            log.error(app + " publish error!");
            log.error("message：" + e.getMessage());
        }
    }

    /**
     * 根据规则路径和服务名称获取规则
     *
     * @param rulePath
     * @param appName
     * @param zkClient
     * @param converter
     * @return
     */
    public static <T> List<T> getRules(String rulePath,
                                       String appName,
                                       CuratorFramework zkClient,
                                       Converter<String, List<T>> converter) {
        try {
            String path = String.format(rulePath, appName);
            byte[] bytes = zkClient.getData().forPath(path);
            if (null == bytes || bytes.length == 0) {
                return new ArrayList<>();
            }
            String s = new String(bytes);
            List<T> convert = converter.convert(s);
            return convert;
        } catch (Exception e) {
            log.warn(appName + " getRules error!");
            log.warn("message：" + e.getMessage());
        }
        return new ArrayList();
    }
}